#ifndef NWAYMERGE_H
#define	NWAYMERGE_H

#include "../Constantes.h"
#include "registroMatrizInicial.h"
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <math.h>
#include <stdlib.h>
#include <cstdlib>
#include <string.h>
#include <new>


class NWayMerge{
public:
    NWayMerge();
    NWayMerge(char* rutaRepo);
    NWayMerge(const NWayMerge& orig);
    virtual ~NWayMerge();
    
    void mergeDeNVias();
    void persisitirCantTerminosDistintos();
    void persistirTerminoDistinto(std::fstream& fd,unsigned long int j,std::string& terminoAPersistir);
    void creoArchConTodosLosTermDistintos(std::fstream*& fdArchTermDistintos);
    void cierroYLiberoArchTermDistintos(std::fstream*& fdArchTermDistintos);
    void setDirectorioAMergear(char* directorio);
    void setRaizDeCantArchsAMergear();
    unsigned long int getCantTerminoDistintos();
    void removeContenidoCarpetaSalidas();
    
private:
    char* rutaRepositorio;
    unsigned int raizDeCantArchRepositorio;
    unsigned long int cantTerminosDistintos;
    unsigned int  cantArchAMergear;
    unsigned int cantConj;

    int crearCarpetaParticionesMergeSiNoExiste(std::string strCarpetaParticionesMerge);
    int crearCarpetaIndiceFinal(std::string strCarpetaIndiceFinal);
    int crearCarpetasDelMerge();
    void borrarParticionesMerge(DIR* dirCarpetaMerge);
    void borrarIndicesUnitarios(DIR* dirCarpetaSalidas);
    void borrarCarpetaMerge();
    void crearArchFinalDelNWayMerge(std::fstream*& fdMatrizInicial);
    unsigned int contarCantArchivosAMergear();
//    void contabilizarTerminosDistintos(std::fstream*& fdArchTermDistintos,std::string& terminoMinimoAnterior,registroMatrizInicial** vectorDeRegistrosEntrada, unsigned int& posMinimo);
    void contabilizarTerminosDistintos(std::string& terminoMinimoAnterior, std::string terminoActual);


    unsigned int obtengoPosicionTermMin(registroMatrizInicial** vecDeRegistrosAMergear)const; //Este const es para que no cambie nada mientras trabaja
    void persistirDatosEnMatIni(std::fstream*& fdMatrizInicial,unsigned char largoTermino,registroMatrizInicial** vectorDeRegistrosEntrada,unsigned int& posMinimo,int& nroDocLeido,int& repeticionesLeidas);
    /* *** FASE1 *** */
    void fase1InicializarVectores(registroMatrizInicial**& vectorDeRegistrosEntrada,std::fstream*& vecArchsEntrada,
                                 std::fstream**& vecArchsSalida);
    void fase1crearParticionesDeSalida(unsigned int cantConj,std::fstream**& vecArchsSalida);
    void fase1PosicionarSoloSobreArchsAMergear(struct dirent*& entry,DIR*& ruta);
    void fase1cargarVecRegsEntrada(unsigned int j,struct dirent* entry,std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada);
    void fase1EscribirMenorEnLaParticionDeSalida(unsigned int posMinimo,unsigned int cantConjProcesados,registroMatrizInicial**& vectorDeRegistrosEntrada,
													std::fstream**& vecArchsSalida);
    void fase1LeerNuevoRegDelArchQueConteniaMinimo(unsigned int posMinimo,unsigned int cantConjProcesados,unsigned int nroDoc,
    												std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada);
    void fase1CerrarYLiberarArchSalidaDeEsteConjProcesado(unsigned int cantConjProcesados,std::fstream**& vecArchsSalida);
    void fase1CerrarConjArchRecienProcesados(bool ultimoConjunto,unsigned int cantArchSinProcesar,std::fstream*& vecArchsEntrada);
    void fase1LiberarRecursosQueNoVoyUsarMas(std::fstream*& vecArchsEntrada,std::fstream**& vecArchsSalida,
    													registroMatrizInicial**& vectorDeRegistrosEntrada);
    void fase1NWayMerge(unsigned int cantConj);
    /* ********************
     * *** NUEVO FASE 1 ***
     * ******************** */
    void obtengoPosicionesOrdenadasTermMinEnVecReg(unsigned int cantTerminosMin,unsigned int*& vecTempPosTermMin,registroMatrizInicial**  vecDeRegistrosAMergear);
    void fase1cargarPosicionesTermino(unsigned int j,unsigned int repeticionesLeidas,unsigned int*& vecPosTerm,const char* nombreArch,
										std::fstream*& vecArchsEntrada);
    void fase1persistirPosicionesTerminoEnArchQueCree(unsigned int cantConjProcesados,unsigned int repeticionesLeidas, unsigned int* vecPosTerm,
    															std::fstream**& vecArchsSalida);
    unsigned int obtenerCantTerminosMinimo(registroMatrizInicial**  vecDeRegistrosAMergear) const;
    /* ************************
	 * *** FIN NUEVO FASE 1 ***
	 * ************************ */

    /* ********************
	 * *** NUEVO FASE 2 ***
	 * ******************** */
    unsigned int fase2obtengoPosicionTermMin(registroMatrizInicial**  vecDeRegistrosAMergear) const;
    void fase2cargarPosicionesTermino(unsigned int j,unsigned int frecTermEnDoc,unsigned int*& vecPosTerm,std::fstream*& vecArchsEntrada);
    void fase2CargarDatosNuevoRegDeVecArchEntradaEnPosMinimo(unsigned int posMinimo,unsigned int nroDocLeido,std::fstream*& vecArchsEntrada,
    																	registroMatrizInicial**& vectorDeRegistrosEntrada);
    void fase2PersistirTerminosMinimosIgualesEnArchFinal(unsigned int cantDocsApareceEsteTerm,std::list<registroMatrizInicial> listaDeMismoTerminoMinimo,
    																std::fstream*& fdMatrizInicial);
    void fase2persistirPosicionesTerminoEnArchFinal(unsigned int repeticionesLeidas, unsigned int* vecPosTerm,std::fstream*& fdMatrizInicial);
    /* ************************
	 * *** FIN NUEVO FASE 2 ***
	 * ************************ */
    /* *** FASE2 *** */
    void fase2inicializarVectores(const unsigned int& cantConj,registroMatrizInicial**& vectorDeRegistrosEntrada,std::fstream*& vecArchsEntrada);
    void fase2cargarVecRegsEntradaConRegsDeArchQueCree(unsigned int j,std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada);
    void fase2CerrarConjArchRecienProcesados(unsigned int cantConj,std::fstream*& vecArchsEntrada);
    void fase2CerrarYLiberarArchivoFinal(std::fstream*& fdMatrizInicial);
    void fase2NWayMerge(unsigned int cantConj);

    void reverse(char s[]);
    void itoa(int n, char s[]);
    unsigned int round(float x);
};

#endif	/* NWAYMERGE_H */

